package com.aliyun.cloudcallcenter.crm.aliyun.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.cloudcallcenter.crm.aliyun.CallCenterServiceException;
import com.aliyun.cloudcallcenter.crm.aliyun.manager.UserManager;
import com.aliyun.cloudcallcenter.crm.model.User;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.BearerTokenCredentials;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import java.security.InvalidParameterException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

/**
 * @author edward
 * @date 2017/11/15
 */
@RestController
public class CccController {

    private static final String REGION = "cn-shanghai";
    private static final String PRODUCT = "CCC";
    private static final String ENDPOINT = "CCC";
    private static final String DOMAIN = "ccc.cn-shanghai.aliyuncs.com";
    private static final String VERSION = "2020-07-01";

    private final Object locker = new Object();

    @Autowired
    private UserManager userManager;

    private static final Logger logger = LoggerFactory.getLogger(CccController.class);


    public static void main(String[] args) {
        String jsonString = "{\"HttpStatusCode\":200,\"RequestId\":\"4322BD50-ACF5-4527-877B-0FA34CBBF331\","
                + "\"Success\":true,\"Code\":\"OK\",\"SkillLevels\":{\"SkillLevel\":[{\"SkillLevelId\":\"15831\","
                + "\"Skill\":{\"OutboundPhoneNumbers\":{\"PhoneNumber\":[]},"
                + "\"InstanceId\":\"dcbdbe37-b966-48c1-b8d7-dd6574190db4\",\"SkillGroupName\":\"e69041\","
                + "\"SkillGroupId\":\"1cf05ff4-1ce6-4d71-919e-d56a48bb2059\"},\"Level\":5}]}}";

        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        JSONObject newObject = new JSONObject();

        copyObject(newObject, jsonObject);

        String result = JSONObject.toJSONString(newObject, true);

        System.out.println(result);
    }

    private static void copyArray(JSONArray destination, JSONArray source) {
        Iterator<Object> iterator = source.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            if (object instanceof JSONObject) {
                JSONObject newObject = new JSONObject();
                destination.add(newObject);
                copyObject(newObject, (JSONObject) object);
            } else if (object instanceof JSONArray) {
                JSONArray newArray = new JSONArray();
                destination.add(newArray);
                copyArray(newArray, (JSONArray) object);
            } else {
                destination.add(object);
            }
        }
    }

    public static void copyObject(JSONObject destination, JSONObject source) {
        for (Entry<String, Object> entry : source.entrySet()) {
            String key = entry.getKey().trim();
            if (key.length() > 1) {
                key = key.substring(0, 1).toLowerCase() + key.substring(1);
            } else if (key.length() == 1) {
                key = key.toUpperCase();
            } else {
                continue;
            }

            Object object = entry.getValue();

            if (object instanceof JSONObject) {
                JSONObject tempObject = (JSONObject) object;
                if (tempObject.entrySet().size() == 1) {
                    Object theOne = tempObject.entrySet().iterator().next().getValue();
                    if (theOne instanceof JSONArray) {
                        JSONArray newArray = new JSONArray();
                        destination.put(key, newArray);
                        copyArray(newArray, (JSONArray) theOne);
                        continue;
                    }
                }
                JSONObject newObject = new JSONObject();
                destination.put(key, newObject);
                copyObject(newObject, (JSONObject) object);
            } else if (object instanceof JSONArray) {
                JSONArray newArray = new JSONArray();
                destination.put(key, newArray);
                copyArray(newArray, (JSONArray) object);
            } else {
                destination.put(key, object);
            }
        }
    }

    /**
     * 前端调用云呼API入口
     * @param principal principal
     * @param httpServletRequest request
     * @return 结果
     */
    @RequestMapping(value = "/aliyun/ccc/api", method = RequestMethod.POST)
    public String call(Principal principal, HttpServletRequest httpServletRequest) {
        User user = userManager.findByUserName(principal.getName());
        String action = httpServletRequest.getParameter("action");
        String request = httpServletRequest.getParameter("request");

        return invokeApiByAk(user.getUserName(), action, request);
    }

    /**
     * 用以方便调试
     *
     * @param principal
     * @param httpServletRequest
     * @param action
     * @param request
     * @return
     */
    @RequestMapping(value = "/aliyun/ccc/api/debug", method = RequestMethod.GET)
    public String get(Principal principal, HttpServletRequest httpServletRequest,
                      @RequestParam String action, @RequestParam String request) throws ClientException {
        User user = userManager.findByUserName(principal.getName());

        return invokeApiByAk(user.getUserName(), action, request);
    }

    /**
     * AK方式调用API
     * @param loginName 登录名
     * @param action 接口名
     * @param request 请求参数
     * @return 结果
     */
    private String invokeApiByAk(String loginName, String action, String request) {
        /**
         * 使用CommonAPI调用POP API时，和使用传统产品SDK相比，请求和返回参数的格式都有所不同，因此需要进行一定的格式转换。
         */
        CommonRequest commonRequest = new CommonRequest();
        commonRequest.setDomain(DOMAIN);
        commonRequest.setVersion(VERSION);
        commonRequest.setAction(action);
        JSONObject jsonObject = JSONObject.parseObject(request);

        for (Entry<String, Object> entry : jsonObject.entrySet()) {
            String key = entry.getKey().trim();
            if (key.length() > 1) {
                key = key.substring(0, 1).toUpperCase() + key.substring(1);
            } else if (key.length() == 1) {
                key = key.toUpperCase();
            } else {
                continue;
            }
            commonRequest.putQueryParameter(key, String.valueOf(entry.getValue()));
        }

        CommonResponse response = null;
        try {
            response = getCccClient(loginName).getCommonResponse(commonRequest);
            System.out.println(JSONObject.toJSONString(response.getData()));
        } catch (ClientException e) {
            logger.error("Failed to invoke open API, request=" + JSON.toJSONString(commonRequest), e);
            throw new CallCenterServiceException(e.getRequestId(), e.getErrCode(), e.getMessage());
        }

        JSONObject jsonResult = JSONObject.parseObject(response.getData());
        JSONObject newJsonResult = new JSONObject();
        copyObject(newJsonResult, jsonResult);
        return JSONObject.toJSONString(newJsonResult);
    }

    private synchronized IAcsClient getCccClient(String loginName) {
        DefaultAcsClient client = null;
        User user = userManager.findByUserName(loginName);
        client = createClient(user.getAk(), user.getSk());
        return client;
    }

    private DefaultAcsClient createClient(String accessKeyId, String secret) {
        try {
            DefaultProfile.addEndpoint(ENDPOINT, REGION, PRODUCT, DOMAIN);
        } catch (ClientException e) {
            logger.error(e.getMessage());
        }
        if (accessKeyId == null || secret == null) {
            throw new InvalidParameterException("ak, sk may not be null.");
        }
        IClientProfile profile = DefaultProfile.getProfile(REGION, accessKeyId, secret);
        return new DefaultAcsClient(profile);
    }
}
